home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Macintosh Tracker 1.20 / source / Server⁄Tracker 4.0 / main.c < prev    next >
Encoding:
Text File  |  1994-02-01  |  15.0 KB  |  568 lines  |  [TEXT/KAHL]

  1. /* main.c */
  2.  
  3. /* plays sound/noisetracker files on Sparc, silicon graphics.
  4.  * Authors  : Liam Corner - zenith@dcs.warwick.ac.uk
  5.  *            Marc Espie - espie@ens.fr
  6.  *            Steve Haehnichen - shaehnic@ucsd.edu
  7.  *            Andrew Leahy - alf@st.nepean.uws.edu.au
  8.  *
  9.  * Usage    : tracker <filename> 
  10.  *  this version plays compressed files as well.
  11.  */
  12.  
  13. /* $Id: main.c,v 4.2 1994/01/13 09:16:00 espie Exp espie $
  14.  * $Log: main.c,v $
  15.  * Revision 4.2  1994/01/13  09:16:00  espie
  16.  * *** empty log message ***
  17.  *
  18.  * Revision 1.10  1994/01/12  16:12:34  espie
  19.  * Last minute changes.
  20.  *
  21.  * Revision 4.1  1994/01/12  16:11:07  espie
  22.  * Last minute changes.
  23.  *
  24.  * Revision 4.0  1994/01/11  17:49:27  espie
  25.  * Base main.c for unix and others.
  26.  *
  27.  * Revision 1.11  1994/01/09  17:36:22  Espie
  28.  * Generalized open.c.
  29.  *
  30.  * Revision 1.10  1994/01/09  04:50:56  Espie
  31.  * ?
  32.  *
  33.  * Revision 1.9  1994/01/08  03:55:43  Espie
  34.  * Slight input/output changes.
  35.  * No more call to create_notes_table().
  36.  *
  37.  * Revision 1.8  1994/01/08  02:04:21  Espie
  38.  * Some notice to status.
  39.  *
  40.  * Revision 1.7  1994/01/06  22:32:42  Espie
  41.  * Use new pref scheme.
  42.  *
  43.  * Revision 1.6  1994/01/05  16:10:49  Espie
  44.  * *** empty log message ***
  45.  *
  46.  * Revision 1.5  1994/01/05  14:54:09  Espie
  47.  * *** empty log message ***
  48.  *
  49.  * Revision 1.4  1994/01/05  13:50:43  Espie
  50.  * Cosmetic change.
  51.  *
  52.  * Revision 1.3  1993/12/28  13:54:44  Espie
  53.  * Use info facility instead of printf for usage message.
  54.  *
  55.  * Revision 1.2  1993/12/26  18:54:21  Espie
  56.  * Modified in a more consistent way.
  57.  *
  58.  * Revision 1.1  1993/12/26  00:55:53  Espie
  59.  * Initial revision
  60.  *
  61.  * Revision 3.20  1993/12/04  17:15:18  espie
  62.  * New version.
  63.  *
  64.  * Revision 3.19  1993/12/04  16:12:50  espie
  65.  * Options changes.
  66.  *
  67.  * Revision 3.18  1993/12/02  15:45:33  espie
  68.  * Changed extended file semantics.
  69.  *
  70.  * Revision 3.17  1993/11/17  15:31:16  espie
  71.  * New version.
  72.  *
  73.  * Revision 3.16  1993/11/11  20:00:03  espie
  74.  * Amiga support.
  75.  *
  76.  * Revision 3.15  1993/08/04  11:55:21  espie
  77.  * Fixed upo previous song bug.
  78.  *
  79.  * Revision 3.13  1993/07/18  10:39:44  espie
  80.  * Added forking under unix. Experimental...
  81.  *
  82.  * Revision 3.11  1993/05/09  14:06:03  espie
  83.  * Fixed up bug with mix option no longer working.
  84.  *
  85.  * Revision 3.10  1993/04/25  15:13:36  espie
  86.  * Force new version.
  87.  *
  88.  * Revision 3.9  1993/01/15  14:00:28  espie
  89.  * Added bg/fg test.
  90.  *
  91.  * Revision 3.7  1992/12/03  15:00:50  espie
  92.  * restore stty.
  93.  *
  94.  * Revision 3.5  1992/11/24  10:51:19  espie
  95.  * Added loads of new options.
  96.  *
  97.  * Revision 3.3  1992/11/22  17:20:01  espie
  98.  * Augmented usage.
  99.  *
  100.  * Revision 3.2  1992/11/20  14:53:32  espie
  101.  * Added finetune.
  102.  *
  103.  * Revision 3.1  1992/11/19  20:44:47  espie
  104.  * Protracker commands.
  105.  *
  106.  * Revision 3.0  1992/11/18  16:08:05  espie
  107.  * New release.
  108.  *
  109.  * Revision 2.20  1992/11/17  17:06:25  espie
  110.  * Added PREVIOUS_SONG handling ???
  111.  * Use streamio for new interface (obsolescent signal handlers), and
  112.  * related changes.
  113.  * Cleaned up path reader, and better signal handling.
  114.  * Support for open_file.
  115.  * Added imask.
  116.  * Use transparent decompression/path lookup through open_file/close_file.
  117.  * Added setup_audio().
  118.  * Added some frequency/oversample/stereo change on the fly.
  119.  * Necessitates rightful closing/reopening of audio.
  120.  * Added compression methods. Changed getopt.
  121.  * Separated mix/stereo stuff.
  122.  * Added transpose feature.
  123.  * Added possibility to get back to MONO for the sgi.
  124.  * Added stereo capabilities to the indigo version.
  125.  * Added recovery and reread for automatic recognition
  126.  * of old/new tracker files.
  127.  * Added two level of fault tolerancy.
  128.  * Added more rational options.
  129.  * Moved almost everything to audio and automaton.
  130.  * Structured part of the code, especially replay ``automaton''
  131.  * and setting up of effects.
  132.  *
  133.  * Revision 1.26  1991/11/17  17:09:53  espie
  134.  * Added missing prototypes.
  135.  * Some more info while loading files.
  136.  * Added FAULT env variable, FAULT resistant playing,
  137.  * for playing modules which are not quite correct.
  138.  * Serious bug: dochangespeed was not reset all the time.
  139.  * Check all these parameters, they MUST be reset for
  140.  * each new song.
  141.  * Fixed a stupid bug: when env variable LOOPING was
  142.  * undefined, we got a segv on strcmp.
  143.  * Now we just test for its existence, since this is
  144.  * about all we want...
  145.  * Bug correction: when doing arpeggio, there might not
  146.  * be a new note, so we have to save the old note value
  147.  * and do the arppeggio on that note.
  148.  * Completely added control with OVERSAMPLE and FREQUENCY.
  149.  * Added control flow.
  150.  * Added pipe decompression, so that now you can do
  151.  * str32 file.Z directly.
  152.  * stdin may go away.
  153.  * Added arpeggio.
  154.  * Added vibslide and portaslide.
  155.  * Added speed command.
  156.  * Added signal control.
  157.  * Error checking: there shouldn't be that many
  158.  * segv signals any more.
  159.  * Moved every command to commands.c.
  160.  * Added some debug code for showing the full
  161.  * sequence for a file.
  162.  * Corrected the bug in volume slide: there is
  163.  * no default value, i.e., if it is 0, it is 0,
  164.  * as stupid as it may seem.
  165.  * Added vibrato.
  166.  * Added fastskip/corrected skip.
  167.  * Modified control flow of the player till
  168.  * it looks like something reasonable (i.e.,
  169.  * the structure is more natural and reflects
  170.  * the way stuff is played actually...)
  171.  * Do not restart the sound when we change instruments
  172.  * on the fly. A bit strange, but it works that way.
  173.  * Modified main to use new data structures.
  174.  * The sound player is MUCH cleaner, it uses now
  175.  * a 3-state automaton for each voice.
  176.  * Corrected ruckus with data type of sample.
  177.  */
  178.      
  179.  
  180. #include "defs.h"
  181.  
  182. #include <stdio.h>
  183. #include <signal.h>
  184. #include <stdlib.h>
  185. #include <string.h>
  186. #ifdef MALLOC_NOT_IN_STDLIB
  187. #include <malloc.h>
  188. #endif
  189. #include <ctype.h>
  190. #ifdef VOLUME_CONTROL
  191. #ifdef __hpux
  192. #define true /* kludge to avoid typedef of boolean (name clash with macro) */
  193. #include <audio/Alib.h>
  194. #undef true
  195. AGainDB    volume = -20;
  196. char use_speaker = 0;
  197. #endif
  198. #endif
  199.  
  200.      
  201. #include "song.h"
  202. #include "extern.h"
  203. #include "options.h"
  204.  
  205. #include "getopt.h"
  206. #include "tags.h"
  207. #include "prefs.h"
  208.      
  209. ID("$Id: main.c,v 4.2 1994/01/13 09:16:00 espie Exp espie $")
  210.  
  211.  
  212. LOCAL void print_usage()
  213.    {
  214.    GENERIC handle;
  215.    
  216.    handle = begin_info("Usage");
  217.    info(handle, "Usage: tracker [options] filename [...]");
  218.    info(handle, "-help               Display usage information");
  219.    info(handle, "-quiet              Print no output other than errors");
  220.    info(handle, "-picky              Do not tolerate any faults (default is to ignore most)");
  221.    info(handle, "-tolerant           Ignore all faults");
  222.    info(handle, "-mono               Select single audio channel output");
  223.    info(handle, "-stereo             Select dual audio channel output");
  224.    info(handle, "-verbose            Show text representation of song");
  225.    info(handle, "-repeats <count>    Number of repeats (0 is forever) (default 1)");
  226.    info(handle, "-speed <speed>      Song speed.  Some songs want 60 (default 50)");
  227.    info(handle, "-mix <percent>      Percent of channel mixing. (0 = spatial, 100 = mono)");
  228.    info(handle, "-new -old -both     Select default reading type (default is -both)");
  229.    info(handle, "-frequency <freq>   Set playback frequency in Hz");
  230.    info(handle, "-oversample <times> Set oversampling factor");
  231.    info(handle, "-transpose <n>      Transpose all notes up");
  232.    info(handle, "-scroll             Show what's going on");
  233.    info(handle, "-sync               Try to synch audio output with display");
  234. #ifdef VOLUME_CONTROL
  235.     info(handle, "-speaker                 Output audio to internal speaker");
  236.     info(handle, "-volume <n>         Set volume in dB");
  237. #endif
  238.    info(handle, "");
  239.    info(handle, "RunTime:");
  240.    info(handle, "e,x     exit program");
  241.    info(handle, "n       next song");
  242.    info(handle, "p       restart/previous song");
  243.    info(handle, ">       fast forward");
  244.    info(handle, "<       rewind");
  245.    info(handle, "S       NTSC tempo\t s\tPAL tempo");
  246.    end_info(handle);
  247.    }
  248.  
  249. /* Command-line options. */
  250. LOCAL struct long_option long_options[] =
  251. {
  252.    {"help",                0, 'H', OPT_HELP},
  253.    {"quiet",               0, 'Q', OPT_QUIET}, 
  254.    {"picky",               0, 'P', OPT_PICKY},
  255.    {"tolerant",            0, 'L', OPT_TOLERANT},
  256.    {"new",                 0, 'N', OPT_NEWONLY},
  257.    {"old",                 0, 'O', OPT_OLDONLY},
  258.    {"both",                0, 'B', OPT_BOTH},
  259.    {"mono",                0, 'M', OPT_MONO},
  260.    {"stereo",              0, 'S', OPT_STEREO},
  261.    {"verbose",             0, 'V', OPT_VERBOSE},
  262.    {"frequency",           1, 'f', OPT_FREQUENCY},
  263.    {"oversample",          1, 'o', OPT_OVERSAMPLE},
  264.    {"transpose",           1, 't', OPT_TRANSPOSE},
  265.    {"repeats",             1, 'r', OPT_REPEATS},
  266.    {"speed",               1, 's', OPT_SPEED},
  267.    {"mix",                 1, 'm', OPT_MIX},
  268.    {"start",               1, 'X', OPT_START},
  269.    {"cut",                 1, '-', OPT_CUT},
  270.    {"add",                 1, '+', OPT_ADD},
  271.    {"scroll",              0, 'v', OPT_SHOW},
  272.    {"sync",                0, '=', OPT_SYNC},
  273. #ifdef VOLUME_CONTROL
  274.     {"speaker",                    0, '#', OPT_SPEAKER},
  275.     {"volume",                    1, 'u', OPT_VOLUME},
  276. #endif
  277.    {0,                     0,  0 , 0}
  278. };
  279.  
  280.  
  281. /* global variable to catch various types of errors
  282.  * and achieve the desired flow of control
  283.  */
  284. int error;
  285.  
  286. LOCAL int optvalue(def)
  287. int def;
  288.    {
  289.    int d;
  290.  
  291.    if (sscanf(optarg, "%d", &d) == 1)
  292.       return d;
  293.    else
  294.       {
  295.       optind--;
  296.       return def;
  297.       }
  298.    }
  299.  
  300. LOCAL struct song *do_read_song(name, type)
  301. char *name;
  302. int type;
  303.    {
  304.    struct song *song;
  305.    struct exfile *file;
  306.  
  307.    file = open_file(name, "r", getenv("MODPATH"));
  308.    if (!file)
  309.       return NULL;
  310.    song = read_song(file, type); 
  311.    close_file(file);
  312.    return song;
  313.    }
  314.  
  315. LOCAL int ask_freq;
  316. LOCAL int oversample;
  317. LOCAL int stereo;
  318. LOCAL int start;
  319. LOCAL int transpose;
  320.  
  321.  
  322. LOCAL void parse_options(argc, argv)
  323. int argc;
  324. char *argv[];
  325.    {
  326.    int c;
  327.    
  328.    while ((c = getlongopt(argc, argv, long_options))
  329.       != BAD_OPTION)
  330.       switch(c)
  331.          {
  332.         case OPT_CUT:
  333.         case OPT_ADD:
  334.             {
  335.             int i;
  336.             unsigned long imask = 0;
  337.       
  338.             for (i = 0; optarg[i]; i++)
  339.                 {
  340.                 char c = tolower(optarg[i]);
  341.  
  342.                 if (c >= '1' && c <= '9')
  343.                     imask |= 1<< (c-'1');
  344.                 else if (c >= 'a' && c <= 'z')
  345.                     imask |= 1 << (c-'a'+9);
  346.                 }
  347.             if (c == OPT_ADD)
  348.                 set_pref_scalar(PREF_IMASK, imask);
  349.             else
  350.                 set_pref_scalar(PREF_IMASK, ~imask);
  351.             }        
  352.          break;
  353.       case OPT_OLDONLY:   /* old tracker type */
  354.          set_pref_scalar(PREF_TYPE, OLD);
  355.          break;
  356.       case OPT_NEWONLY:   /* new tracker type */
  357.          set_pref_scalar(PREF_TYPE, NEW);
  358.          break;
  359.       case OPT_SHOW:
  360.          set_pref_scalar(PREF_SHOW, TRUE);
  361.          break;
  362.       case OPT_SYNC:
  363.          set_pref_scalar(PREF_SYNC, TRUE);
  364.          break;
  365.       case OPT_BOTH:   /* both tracker types */
  366.          set_pref_scalar(PREF_TYPE, BOTH);
  367.          break;
  368.       case OPT_REPEATS:   /* number of repeats */
  369.          set_pref_scalar(PREF_REPEATS, optvalue(0));
  370.          break;
  371.       case OPT_SPEED:  
  372.          set_pref_scalar(PREF_SPEED, optvalue(50));
  373.          break;
  374.       case OPT_MONO:  
  375.          stereo = FALSE;
  376.          break;
  377.       case OPT_STEREO:  
  378.          stereo = TRUE;
  379.          break;
  380.       case OPT_OVERSAMPLE:  
  381.          oversample = optvalue(1);
  382.          break;
  383.       case OPT_FREQUENCY:
  384.          ask_freq = optvalue(0);
  385.          break;
  386.       case OPT_TRANSPOSE:
  387.          transpose = optvalue(0);
  388.          break;
  389.       case OPT_PICKY:
  390.          set_pref_scalar(PREF_TOLERATE, 0);
  391.          break;
  392.       case OPT_TOLERANT:
  393.          set_pref_scalar(PREF_TOLERATE, 0);
  394.          break;
  395.       case OPT_MIX:     /* % of channel mix. 
  396.                          * 0->full stereo, 100->mono */
  397.          set_mix(optvalue(30));
  398.          break;
  399.       case OPT_START:
  400.          start = optvalue(0);
  401.          break;
  402.       case OPT_HELP:
  403.          print_usage();
  404.          end_all(0);
  405.          /* NOTREACHED */
  406.       case OPT_VERBOSE:
  407.          set_pref_scalar(PREF_DUMP, TRUE);
  408.             break;
  409. #ifdef VOLUME_CONTROL
  410.         case OPT_VOLUME:
  411.             volume = optvalue(-20);
  412.             break;
  413.         case OPT_SPEAKER:
  414.             use_speaker = 1;
  415.             break;
  416. #endif
  417.          }
  418.    }
  419.  
  420. LOCAL struct song *load_song(name)
  421. char *name;
  422.    {
  423.    struct song *song;
  424.    char *buffer;
  425.    int i, j;
  426.    
  427.    i = strlen(name);
  428.    
  429.    for (j = i; j > 0; j--)
  430.       if (name[j] == '/' || name[j] == '\\')
  431.          {
  432.          j++;
  433.          break;
  434.          }
  435.    
  436.    buffer = malloc( i - j + 5);
  437.    if (buffer)
  438.       {
  439.       sprintf(buffer, "%s...", name + j);
  440.       status(buffer);
  441.       }
  442.  
  443.    
  444.    switch(get_pref_scalar(PREF_TYPE))
  445.       {
  446.    case BOTH:
  447.       song = do_read_song(name, NEW);
  448.       if (song)
  449.             break;
  450.       /* FALLTHRU */
  451.    case OLD:
  452.       song = do_read_song(name, OLD);
  453.       break;
  454.       /* this is explicitly flagged as a new module,
  455.        * so we don't need to look for a signature.
  456.        */
  457.    case NEW:
  458.       song = do_read_song(name, NEW_NO_CHECK);
  459.       break;
  460.       }
  461.    status(0);
  462.     return song;
  463.    }
  464.  
  465. int main(argc, argv)
  466. int argc;
  467. char **argv;
  468.    {
  469.    struct song *song;
  470.    boolean *is_song;
  471.    int i;
  472.  
  473.    struct tag *result;
  474.  
  475.    is_song = (boolean *)malloc(sizeof(boolean) * argc);
  476.    if (!is_song)
  477.       end_all("No memory left");
  478.  
  479.    for (i = 0; i < argc; i++)
  480.       is_song[i] = FALSE;        /* For termination */
  481.  
  482.    start = 0;
  483.    set_pref_scalar(PREF_IMASK, 0);
  484.    set_pref_scalar(PREF_BCDVOL, 0);
  485.    set_pref_scalar(PREF_DUMP, FALSE);
  486.    set_pref_scalar(PREF_SHOW, FALSE);
  487.    set_pref_scalar(PREF_SYNC, FALSE);
  488.    set_pref_scalar(PREF_TYPE, BOTH);
  489.    set_pref_scalar(PREF_REPEATS, 1);
  490.    set_pref_scalar(PREF_SPEED, 50);
  491.    set_pref_scalar(PREF_TOLERATE, 1);
  492.  
  493.    if (argc == 1)
  494.       {
  495.       print_usage();
  496.       end_all(0);
  497.       }
  498.  
  499.    ask_freq = read_env("FREQUENCY", 0);
  500.    oversample = read_env("OVERSAMPLE", 1);
  501.    transpose = read_env("TRANSPOSE", 0);
  502.    stereo = !getenv("MONO");
  503.    set_mix(30);
  504.  
  505.  
  506.  
  507.       /* check the command name for default reading type */
  508.  
  509.  
  510.    optind = 1;
  511.    for (optind = 1; optind < argc; optind++)
  512.       {
  513.       parse_options(argc, argv);
  514.       if (optind >= argc)
  515.          end_all(0);
  516.          
  517.    
  518.       song = load_song(argv[optind]);   
  519.       if (song)
  520.          is_song[optind] = TRUE;
  521.       else
  522.          {
  523.          puts("not a song");
  524.          is_song[optind] = FALSE;
  525.          continue;
  526.          }
  527. play_on:
  528.       if (get_pref_scalar(PREF_DUMP))
  529.          dump_song(song); 
  530.       transpose_song(song, transpose);
  531.       setup_audio(ask_freq, stereo, oversample);
  532.       result = play_song(song, start);
  533.       release_song(song);
  534.       status(0);
  535.       while (result = get_tag(result))
  536.          {
  537.          switch (result->type)
  538.             {
  539.          case PLAY_PREVIOUS_SONG:
  540.             optind--;
  541.             while ((optind > 0) && !is_song[optind])
  542.                optind--;
  543.             if (optind == 0)
  544.                end_all(0);
  545.             else
  546.                {
  547.                song = load_song(argv[optind]);
  548.                goto play_on;
  549.                }
  550.             /* NOTREACHED */
  551.          case PLAY_LOAD_SONG:
  552.             song = load_song(result->data.pointer);
  553.             free(result->data.pointer);
  554.             if (song)
  555.                goto play_on;
  556.          default:
  557.             break;
  558.             }
  559.          result++;
  560.          }
  561.             
  562.       }
  563.    end_all(0);
  564.    /* NOTREACHED */
  565.    }
  566.  
  567.  
  568.